text:
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="ChangeListManager">
    <list default="true" id="ecb33044-79ab-48ea-84f8-aa65f50c806c" name="Default" comment="">
      <change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/test/mocha/200.js" />
      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/package.json" afterPath="$PROJECT_DIR$/package.json" />
      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/test/casper/results.xml" afterPath="$PROJECT_DIR$/test/casper/results.xml" />
      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/.idea/dictionaries/tim.xml" afterPath="$PROJECT_DIR$/.idea/dictionaries/tim.xml" />
      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/.idea/workspace.xml" afterPath="$PROJECT_DIR$/.idea/workspace.xml" />
    </list>
    <ignored path="nodeboi.iws" />
    <ignored path=".idea/workspace.xml" />
    <option name="TRACKING_ENABLED" value="true" />
    <option name="SHOW_DIALOG" value="false" />
    <option name="HIGHLIGHT_CONFLICTS" value="true" />
    <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
    <option name="LAST_RESOLUTION" value="IGNORE" />
  </component>
  <component name="ChangesViewManager" flattened_view="true" show_ignored="false" />
  <component name="CreatePatchCommitExecutor">
    <option name="PATCH_PATH" value="" />
  </component>
  <component name="DaemonCodeAnalyzer">
    <disable_hints />
  </component>
  <component name="ExecutionTargetManager" SELECTED_TARGET="default_target" />
  <component name="FavoritesManager">
    <favorites_list name="nodeboi" />
  </component>
  <component name="FileEditorManager">
    <leaf>
      <file leaf-file-name=".gitignore" pinned="false" current="false" current-in-tab="false">
        <entry file="file://$PROJECT_DIR$/.gitignore">
          <provider selected="true" editor-type-id="text-editor">
            <state vertical-scroll-proportion="0.0" vertical-offset="0" max-vertical-offset="460">
              <caret line="16" column="7" selection-start-line="16" selection-start-column="7" selection-end-line="16" selection-end-column="7" />
              <folding />
            </state>
          </provider>
        </entry>
      </file>
      <file leaf-file-name="Gruntfile.js" pinned="false" current="false" current-in-tab="false">
        <entry file="file://$PROJECT_DIR$/Gruntfile.js">
          <provider selected="true" editor-type-id="text-editor">
            <state vertical-scroll-proportion="0.0" vertical-offset="808" max-vertical-offset="2860">
              <caret line="58" column="0" selection-start-line="58" selection-start-column="0" selection-end-line="58" selection-end-column="0" />
              <folding />
            </state>
          </provider>
        </entry>
      </file>
      <file leaf-file-name="200.js" pinned="false" current="false" current-in-tab="false">
        <entry file="file://$PROJECT_DIR$/test/casper/200.js">
          <provider selected="true" editor-type-id="text-editor">
            <state vertical-scroll-proportion="0.0" vertical-offset="0" max-vertical-offset="320">
              <caret line="10" column="0" selection-start-line="10" selection-start-column="0" selection-end-line="10" selection-end-column="0" />
              <folding />
            </state>
          </provider>
        </entry>
      </file>
      <file leaf-file-name="200.js" pinned="false" current="true" current-in-tab="true">
        <entry file="file://$PROJECT_DIR$/test/mocha/200.js">
          <provider selected="true" editor-type-id="text-editor">
            <state vertical-scroll-proportion="0.56122446" vertical-offset="0" max-vertical-offset="400">
              <caret line="11" column="15" selection-start-line="11" selection-start-column="15" selection-end-line="11" selection-end-column="15" />
              <folding />
            </state>
          </provider>
        </entry>
      </file>
      <file leaf-file-name="index.js" pinned="false" current="false" current-in-tab="false">
        <entry file="file://$PROJECT_DIR$/src/scripts/index.js">
          <provider selected="true" editor-type-id="text-editor">
            <state vertical-scroll-proportion="0.0" vertical-offset="0" max-vertical-offset="140">
              <caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
              <folding />
            </state>
          </provider>
        </entry>
      </file>
      <file leaf-file-name="README.md" pinned="false" current="false" current-in-tab="false">
        <entry file="file://$PROJECT_DIR$/README.md">
          <provider selected="true" editor-type-id="text-editor">
            <state vertical-scroll-proportion="-4.8" vertical-offset="0" max-vertical-offset="260">
              <caret line="6" column="65" selection-start-line="6" selection-start-column="65" selection-end-line="6" selection-end-column="65" />
              <folding />
            </state>
          </provider>
        </entry>
      </file>
      <file leaf-file-name="server.js" pinned="false" current="false" current-in-tab="false">
        <entry file="file://$PROJECT_DIR$/server.js">
          <provider selected="true" editor-type-id="text-editor">
            <state vertical-scroll-proportion="0.0" vertical-offset="300" max-vertical-offset="740">
              <caret line="31" column="3" selection-start-line="31" selection-start-column="3" selection-end-line="31" selection-end-column="3" />
              <folding />
            </state>
          </provider>
        </entry>
      </file>
      <file leaf-file-name="index.jade" pinned="false" current="false" current-in-tab="false">
        <entry file="file://$PROJECT_DIR$/app/views/index.jade">
          <provider selected="true" editor-type-id="text-editor">
            <state vertical-scroll-proportion="0.0" vertical-offset="0" max-vertical-offset="300">
              <caret line="4" column="45" selection-start-line="4" selection-start-column="45" selection-end-line="4" selection-end-column="45" />
              <folding />
            </state>
          </provider>
        </entry>
      </file>
    </leaf>
  </component>
  <component name="FindManager">
    <FindUsagesManager>
      <setting name="OPEN_NEW_TAB" value="true" />
    </FindUsagesManager>
  </component>
  <component name="Git.Settings">
    <option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
  </component>
  <component name="IdeDocumentHistory">
    <option name="changedFiles">
      <list>
        <option value="$PROJECT_DIR$/test/casper/200.js" />
        <option value="$PROJECT_DIR$/db/seeds/things,json" />
        <option value="$PROJECT_DIR$/.gitignore" />
        <option value="$PROJECT_DIR$/src/styles/main.scss" />
        <option value="$PROJECT_DIR$/Gruntfile.js" />
        <option value="$PROJECT_DIR$/app/views/index.jade" />
        <option value="$PROJECT_DIR$/README.md" />
        <option value="$PROJECT_DIR$/server.js" />
        <option value="$PROJECT_DIR$/test/mocha/200.js" />
      </list>
    </option>
  </component>
  <component name="JsGruntFileManager">
    <gruntfiles>
      <GruntfileState>
        <alias-tasks>
          <alias-task value="build" />
          <alias-task value="default" />
          <alias-task value="test" />
        </alias-tasks>
        <multi-tasks>
          <GruntMultiTaskState>
            <name>casper</name>
            <targets>
              <target value="all" />
            </targets>
          </GruntMultiTaskState>
          <GruntMultiTaskState>
            <name>concat</name>
            <targets>
              <target value="dev" />
            </targets>
          </GruntMultiTaskState>
          <GruntMultiTaskState>
            <name>cssmin</name>
            <targets>
              <target value="files" />
            </targets>
          </GruntMultiTaskState>
          <GruntMultiTaskState>
            <name>env</name>
            <targets>
              <target value="dev" />
              <target value="test" />
            </targets>
          </GruntMultiTaskState>
          <GruntMultiTaskState>
            <name>express</name>
            <targets>
              <target value="dev" />
              <target value="test" />
            </targets>
          </GruntMultiTaskState>
          <GruntMultiTaskState>
            <name>mongoimport</name>
          </GruntMultiTaskState>
          <GruntMultiTaskState>
            <name>sass</name>
            <targets>
              <target value="dev" />
              <target value="build" />
            </targets>
          </GruntMultiTaskState>
          <GruntMultiTaskState>
            <name>simplemocha</name>
            <targets>
              <target value="all" />
            </targets>
          </GruntMultiTaskState>
          <GruntMultiTaskState>
            <name>uglify</name>
            <targets>
              <target value="files" />
            </targets>
          </GruntMultiTaskState>
          <GruntMultiTaskState>
            <name>watch</name>
            <targets>
              <target value="js" />
              <target value="scss" />
              <target value="views" />
              <target value="express" />
            </targets>
          </GruntMultiTaskState>
        </multi-tasks>
        <gruntfile-path>$PROJECT_DIR$/Gruntfile.js</gruntfile-path>
      </GruntfileState>
    </gruntfiles>
    <initial>false</initial>
  </component>
  <component name="ProjectFrameBounds">
    <option name="y" value="29" />
    <option name="width" value="1366" />
    <option name="height" value="739" />
  </component>
  <component name="ProjectLevelVcsManager" settingsEditedManually="false">
    <OptionsSetting value="true" id="Add" />
    <OptionsSetting value="true" id="Remove" />
    <OptionsSetting value="true" id="Checkout" />
    <OptionsSetting value="true" id="Update" />
    <OptionsSetting value="true" id="Status" />
    <OptionsSetting value="true" id="Edit" />
    <ConfirmationsSetting value="0" id="Add" />
    <ConfirmationsSetting value="0" id="Remove" />
  </component>
  <component name="ProjectReloadState">
    <option name="STATE" value="0" />
  </component>
  <component name="ProjectView">
    <navigator currentView="ProjectPane" proportions="" version="1">
      <flattenPackages />
      <showMembers />
      <showModules />
      <showLibraryContents />
      <hideEmptyPackages />
      <abbreviatePackageNames />
      <autoscrollToSource />
      <autoscrollFromSource />
      <sortByType />
    </navigator>
    <panes>
      <pane id="Scope">
        <subPane subId="Project Files">
          <PATH>
            <PATH_ELEMENT USER_OBJECT="Root">
              <option name="myItemId" value="" />
              <option name="myItemType" value="" />
            </PATH_ELEMENT>
            <PATH_ELEMENT USER_OBJECT="nodeboi">
              <option name="myItemId" value="" />
              <option name="myItemType" value="" />
            </PATH_ELEMENT>
          </PATH>
        </subPane>
      </pane>
      <pane id="ProjectPane">
        <subPane>
          <PATH>
            <PATH_ELEMENT>
              <option name="myItemId" value="nodeboi" />
              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
            </PATH_ELEMENT>
          </PATH>
          <PATH>
            <PATH_ELEMENT>
              <option name="myItemId" value="nodeboi" />
              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
            </PATH_ELEMENT>
            <PATH_ELEMENT>
              <option name="myItemId" value="nodeboi" />
              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
            </PATH_ELEMENT>
          </PATH>
          <PATH>
            <PATH_ELEMENT>
              <option name="myItemId" value="nodeboi" />
              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
            </PATH_ELEMENT>
            <PATH_ELEMENT>
              <option name="myItemId" value="nodeboi" />
              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
            </PATH_ELEMENT>
            <PATH_ELEMENT>
              <option name="myItemId" value="test" />
              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
            </PATH_ELEMENT>
          </PATH>
        </subPane>
      </pane>
    </panes>
  </component>
  <component name="PropertiesComponent">
    <property name="WebServerToolWindowFactoryState" value="false" />
  </component>
  <component name="RunManager">
    <configuration default="true" type="DartUnitRunConfigurationType" factoryName="DartUnit">
      <option name="VMOptions" />
      <option name="arguments" />
      <option name="filePath" />
      <option name="scope" value="ALL" />
      <option name="testName" />
      <method />
    </configuration>
    <configuration default="true" type="DartCommandLineRunConfigurationType" factoryName="Dart Command Line Application">
      <option name="VMOptions" />
      <option name="arguments" />
      <option name="filePath" />
      <option name="name" value="Dart" />
      <option name="saveOutputToFile" value="false" />
      <option name="showConsoleOnStdErr" value="false" />
      <option name="showConsoleOnStdOut" value="false" />
      <method />
    </configuration>
    <configuration default="true" type="CucumberJavaScriptRunConfigurationType" factoryName="Cucumber.js">
      <option name="cucumberJsArguments" />
      <option name="executablePath" />
      <option name="filePath" />
      <method />
    </configuration>
    <configuration default="true" type="JavaScriptTestRunnerKarma" factoryName="Karma" config-file="">
      <envs />
      <method />
    </configuration>
    <configuration default="true" type="JSTestDriver:ConfigurationType" factoryName="JsTestDriver">
      <setting name="configLocationType" value="CONFIG_FILE" />
      <setting name="settingsFile" value="" />
      <setting name="serverType" value="INTERNAL" />
      <setting name="preferredDebugBrowser" value="Chrome" />
      <method />
    </configuration>
    <configuration default="true" type="JavascriptDebugType" factoryName="JavaScript Debug">
      <method />
    </configuration>
    <configuration default="true" type="NodeJSConfigurationType" factoryName="Node.js" working-dir="">
      <method />
    </configuration>
    <list size="0" />
  </component>
  <component name="ShelveChangesManager" show_recycled="false" />
  <component name="TaskManager">
    <task active="true" id="Default" summary="Default task">
      <changelist id="ecb33044-79ab-48ea-84f8-aa65f50c806c" name="Default" comment="" />
      <created>1396280177269</created>
      <updated>1396280177269</updated>
    </task>
    <servers />
  </component>
  <component name="ToolWindowManager">
    <frame x="0" y="29" width="1366" height="739" extended-state="1" />
    <editor active="false" />
    <layout>
      <window_info id="Grunt" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" weight="0.32744783" sideWeight="0.5" order="-1" side_tool="false" content_ui="tabs" />
      <window_info id="Changes" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="-1" side_tool="false" content_ui="tabs" />
      <window_info id="Terminal" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.32744783" sideWeight="0.5" order="-1" side_tool="false" content_ui="tabs" />
      <window_info id="TODO" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="6" side_tool="false" content_ui="tabs" />
      <window_info id="Structure" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
      <window_info id="Project" active="true" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" weight="0.16405667" sideWeight="0.5" order="0" side_tool="false" content_ui="combo" />
      <window_info id="Debug" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.4" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
      <window_info id="Favorites" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="-1" side_tool="true" content_ui="tabs" />
      <window_info id="Event Log" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="-1" side_tool="true" content_ui="tabs" />
      <window_info id="Run" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" />
      <window_info id="Version Control" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="-1" side_tool="false" content_ui="tabs" />
      <window_info id="Cvs" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.25" sideWeight="0.5" order="4" side_tool="false" content_ui="tabs" />
      <window_info id="Message" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
      <window_info id="Ant Build" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
      <window_info id="Find" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
      <window_info id="Commander" active="false" anchor="right" auto_hide="false" internal_type="SLIDING" type="SLIDING" visible="false" weight="0.4" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
      <window_info id="Hierarchy" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.25" sideWeight="0.5" order="2" side_tool="false" content_ui="combo" />
      <window_info id="Inspection" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.4" sideWeight="0.5" order="5" side_tool="false" content_ui="tabs" />
    </layout>
  </component>
  <component name="Vcs.Log.UiProperties">
    <option name="RECENTLY_FILTERED_USER_GROUPS">
      <collection />
    </option>
    <option name="RECENTLY_FILTERED_BRANCH_GROUPS">
      <collection />
    </option>
  </component>
  <component name="VcsContentAnnotationSettings">
    <option name="myLimit" value="2678400000" />
  </component>
  <component name="VcsManagerConfiguration">
    <option name="myTodoPanelSettings">
      <TodoPanelSettings />
    </option>
  </component>
  <component name="XDebuggerManager">
    <breakpoint-manager />
  </component>
  <component name="editorHistoryManager">
    <entry file="file://$PROJECT_DIR$/LICENSE">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0" vertical-offset="0" max-vertical-offset="596">
          <caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/test/casper/results.xml">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0" vertical-offset="0" max-vertical-offset="379">
          <caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/.gitignore">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0" vertical-offset="0" max-vertical-offset="460">
          <caret line="16" column="7" selection-start-line="16" selection-start-column="7" selection-end-line="16" selection-end-column="7" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/src/styles/main.scss">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="-1.3793104" vertical-offset="0" max-vertical-offset="160">
          <caret line="2" column="1" selection-start-line="2" selection-start-column="1" selection-end-line="2" selection-end-column="1" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/public/app.js">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0" vertical-offset="0" max-vertical-offset="392">
          <caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/public/app.min.js">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0" vertical-offset="0" max-vertical-offset="392">
          <caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/app/views/index.jade">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0" vertical-offset="0" max-vertical-offset="300">
          <caret line="4" column="45" selection-start-line="4" selection-start-column="45" selection-end-line="4" selection-end-column="45" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/public/styles.min.css">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0" vertical-offset="0" max-vertical-offset="392">
          <caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/Gruntfile.js">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0" vertical-offset="808" max-vertical-offset="2860">
          <caret line="58" column="0" selection-start-line="58" selection-start-column="0" selection-end-line="58" selection-end-column="0" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/src/scripts/index.js">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0" vertical-offset="0" max-vertical-offset="392">
          <caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/README.md">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="-4.8" vertical-offset="0" max-vertical-offset="260">
          <caret line="6" column="65" selection-start-line="6" selection-start-column="65" selection-end-line="6" selection-end-column="65" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/server.js">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0" vertical-offset="300" max-vertical-offset="740">
          <caret line="31" column="3" selection-start-line="31" selection-start-column="3" selection-end-line="31" selection-end-column="3" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/test/casper/200.js">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0" vertical-offset="0" max-vertical-offset="320">
          <caret line="10" column="0" selection-start-line="10" selection-start-column="0" selection-end-line="10" selection-end-column="0" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/test/mocha/200.js">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.56122446" vertical-offset="0" max-vertical-offset="400">
          <caret line="11" column="15" selection-start-line="11" selection-start-column="15" selection-end-line="11" selection-end-column="15" />
          <folding />
        </state>
      </provider>
    </entry>
  </component>
</project>


text:
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.

defined('MOODLE_INTERNAL') || die;

$functions = array(

    'mod_resource_view_resource' => array(
        'classname'     => 'mod_resource_external',
        'methodname'    => 'view_resource',
        'description'   => 'Simulate the view.php web interface resource: trigger events, completion, etc...',
        'type'          => 'write',
        'capabilities'  => 'mod/resource:view',
        'services'      => array(MOODLE_OFFICIAL_MOBILE_SERVICE)
    ),
    'mod_resource_get_resources_by_courses' => array(
        'classname'     => 'mod_resource_external',
        'methodname'    => 'get_resources_by_courses',
        'description'   => 'Returns a list of files in a provided list of courses, if no list is provided all files that
                            the user can view will be returned.',
        'type'          => 'read',
        'capabilities'  => 'mod/resource:view',
        'services'      => array(MOODLE_OFFICIAL_MOBILE_SERVICE),
    ),
);

redpajama_set_name: RedPajamaGithub


text:
import { StructureElement, Unit, Structure } from '../../../mol-model/structure/structure';
import { ChunkedArray } from '../../../mol-data/util';
import { GridLookup3D } from '../../../mol-math/geometry';
import { OrderedSet, SortedArray } from '../../../mol-data/int';
import { FeatureGroup, FeatureType } from './common';
import { ValenceModelProvider } from '../valence-model';
import { Vec3 } from '../../../mol-math/linear-algebra';
import { getBoundary } from '../../../mol-math/geometry/boundary';

export { Features };

interface Features {
    /** number of features */
    readonly count: number
    /** center x coordinate, in invariant coordinate space */
    readonly x: ArrayLike<number>
    /** center y coordinate, in invariant coordinate space */
    readonly y: ArrayLike<number>
    /** center z coordinate, in invariant coordinate space */
    readonly z: ArrayLike<number>
    readonly types: ArrayLike<FeatureType>
    readonly groups: ArrayLike<FeatureGroup>
    readonly offsets: ArrayLike<number>
    /** elements of this feature, range for feature i is offsets[i] to offsets[i + 1] */
    readonly members: ArrayLike<StructureElement.UnitIndex>

    /** lookup3d based on center coordinates, in invariant coordinate space */
    readonly lookup3d: GridLookup3D<Features.FeatureIndex>
    /** maps unit elements to features, range for unit element i is offsets[i] to offsets[i + 1] */
    readonly elementsIndex: Features.ElementsIndex

    subset(types: ReadonlySet<FeatureType>): Features.Subset
}

namespace Features {
    /** Index into Features data arrays */
    export type FeatureIndex = { readonly '@type': 'feature-index' } & number

    export function setPosition(out: Vec3, unit: Unit, index: FeatureIndex, features: Features) {
        Vec3.set(out, features.x[index], features.y[index], features.z[index]);
        Vec3.transformMat4(out, out, unit.conformation.operator.matrix);
        return out;
    }

    /** maps unit elements to features, range for unit element i is offsets[i] to offsets[i + 1] */
    export type ElementsIndex = {
        /** feature indices */
        readonly indices: ArrayLike<FeatureIndex>
        /** range for unit element i is offsets[i] to offsets[i + 1] */
        readonly offsets: ArrayLike<number>
    }

    export type Data = {
        count: number
        x: ArrayLike<number>
        y: ArrayLike<number>
        z: ArrayLike<number>
        types: ArrayLike<FeatureType>
        groups: ArrayLike<FeatureGroup>
        offsets: ArrayLike<number>
        members: ArrayLike<StructureElement.UnitIndex>
    }

    export type Subset = {
        readonly indices: OrderedSet<FeatureIndex>
        readonly lookup3d: GridLookup3D
    }

    export function createElementsIndex(data: Data, elementsCount: number): ElementsIndex {
        const offsets = new Int32Array(elementsCount + 1);
        const bucketFill = new Int32Array(elementsCount);
        const bucketSizes = new Int32Array(elementsCount);
        const { members, count, offsets: featureOffsets } = data;
        for (let i = 0, il = featureOffsets[count]; i < il; ++i) ++bucketSizes[members[i]];

        let offset = 0;
        for (let i = 0; i < elementsCount; i++) {
            offsets[i] = offset;
            offset += bucketSizes[i];
        }
        offsets[elementsCount] = offset;

        const indices = new Int32Array(offset);
        for (let i = 0; i < count; ++i) {
            for (let j = featureOffsets[i], jl = featureOffsets[i + 1]; j < jl; ++j) {
                const a = members[j];
                const oa = offsets[a] + bucketFill[a];
                indices[oa] = i;
                ++bucketFill[a];
            }
        }

        return { indices: indices as unknown as ArrayLike<FeatureIndex>, offsets };
    }

    export function create(elementsCount: number, data: Data): Features {
        let lookup3d: GridLookup3D<FeatureIndex>;
        let elementsIndex: ElementsIndex;

        return {
            ...data,
            get lookup3d() {
                if (!lookup3d) {
                    const position = { x: data.x, y: data.y, z: data.z, indices: OrderedSet.ofBounds(0 as FeatureIndex, data.count as FeatureIndex) };
                    lookup3d = GridLookup3D(position, getBoundary(position));
                }
                return lookup3d;
            },
            get elementsIndex() {
                return elementsIndex || (elementsIndex = createElementsIndex(data, elementsCount));
            },

            subset: (types: Set<FeatureType>) => createSubset(data, types)
        };
    }

    export function createSubset(data: Data, types: ReadonlySet<FeatureType>): Subset {
        let lookup3d: GridLookup3D;

        const { count, types: _types } = data;
        const _indices = [];
        for (let i = 0; i < count; ++i) {
            if (types.has(_types[i])) _indices.push(i);
        }
        const indices = SortedArray.ofSortedArray<FeatureIndex>(_indices);

        return {
            indices,
            get lookup3d() {
                if (!lookup3d) {
                    const position = { x: data.x, y: data.y, z: data.z, indices };
                    lookup3d = GridLookup3D(position, getBoundary(position));
                }
                return lookup3d;
            }
        };
    }

    export interface Info {
        unit: Unit.Atomic,
        types: ArrayLike<FeatureType>,
        feature: FeatureIndex,
        x: ArrayLike<number>
        y: ArrayLike<number>
        z: ArrayLike<number>
        members: ArrayLike<StructureElement.UnitIndex>,
        offsets: ArrayLike<number>,
        idealGeometry: Int8Array
    }
    export function Info(structure: Structure, unit: Unit.Atomic, features: Features): Info {
        const valenceModel = ValenceModelProvider.get(structure).value;
        if (!valenceModel || !valenceModel.has(unit.id)) throw new Error('valence model required');

        return {
            unit,
            types: features.types,
            feature: -1 as any,
            x: features.x,
            y: features.y,
            z: features.z,
            members: features.members,
            offsets: features.offsets,
            idealGeometry: valenceModel.get(unit.id)!.idealGeometry
        };
    }

    export function position(out: Vec3, info: Info) {
        Vec3.set(out, info.x[info.feature], info.y[info.feature], info.z[info.feature]);
        Vec3.transformMat4(out, out, info.unit.conformation.operator.matrix);
        return out;
    }

    const tmpVecA = Vec3();
    const tmpVecB = Vec3();
    export function distance(infoA: Info, infoB: Info) {
        const elementA = infoA.members[infoA.offsets[infoA.feature]];
        const elementB = infoB.members[infoB.offsets[infoB.feature]];
        infoA.unit.conformation.position(infoA.unit.elements[elementA], tmpVecA);
        infoB.unit.conformation.position(infoB.unit.elements[elementB], tmpVecB);
        return Vec3.distance(tmpVecA, tmpVecB);
    }

    export interface Provider {
        types: Set<FeatureType>
        add: (structure: Structure, unit: Unit.Atomic, featuresBuilder: FeaturesBuilder) => void
    }
    export function Provider(types: FeatureType[], add: Provider['add']): Provider {
        return { types: new Set(types), add };
    }
}

export { FeaturesBuilder };

interface FeaturesBuilder {
    startState: () => void
    pushMember: (x: number, y: number, z: number, member: StructureElement.UnitIndex) => void
    finishState: (type: FeatureType, group: FeatureGroup) => void
    add: (type: FeatureType, group: FeatureGroup, x: number, y: number, z: number, member: StructureElement.UnitIndex) => void
    getFeatures: (elementsCount: number) => Features
}

namespace FeaturesBuilder {
    interface State { x: number, y: number, z: number, offset: number, count: number }

    export function create(initialCount = 2048, chunkSize = 1024, features?: Features): FeaturesBuilder {
        const xCenters = ChunkedArray.create(Float32Array, 1, chunkSize, features ? features.x : initialCount);
        const yCenters = ChunkedArray.create(Float32Array, 1, chunkSize, features ? features.y : initialCount);
        const zCenters = ChunkedArray.create(Float32Array, 1, chunkSize, features ? features.z : initialCount);
        const types = ChunkedArray.create(Uint8Array, 1, chunkSize, features ? features.types : initialCount);
        const groups = ChunkedArray.create(Uint8Array, 1, chunkSize, features ? features.groups : initialCount);
        const offsets = ChunkedArray.create(Uint32Array, 1, chunkSize, features ? features.offsets : initialCount);
        const members = ChunkedArray.create(Uint32Array, 1, chunkSize, features ? features.members : initialCount);

        const state: State = { x: 0, y: 0, z: 0, offset: 0, count: 0 };

        return {
            startState: () => {
                state.x = 0;
                state.y = 0;
                state.z = 0;
                state.offset = members.elementCount;
                state.count = 0;
            },
            pushMember: (x: number, y: number, z: number, member: StructureElement.UnitIndex) => {
                ChunkedArray.add(members, member);
                state.x += x;
                state.y += y;
                state.z += z;
                state.count += 1;
            },
            finishState: (type: FeatureType, group: FeatureGroup) => {
                const { count } = state;
                if (count === 0) return;
                ChunkedArray.add(types, type);
                ChunkedArray.add(groups, group);
                ChunkedArray.add(xCenters, state.x / count);
                ChunkedArray.add(yCenters, state.y / count);
                ChunkedArray.add(zCenters, state.z / count);
                ChunkedArray.add(offsets, state.offset);
            },
            add: (type: FeatureType, group: FeatureGroup, x: number, y: number, z: number, member: StructureElement.UnitIndex) => {
                ChunkedArray.add(types, type);
                ChunkedArray.add(groups, group);
                ChunkedArray.add(xCenters, x);
                ChunkedArray.add(yCenters, y);
                ChunkedArray.add(zCenters, z);
                ChunkedArray.add(offsets, members.elementCount);
                ChunkedArray.add(members, member);
            },
            getFeatures: (elementsCount: number) => {
                ChunkedArray.add(offsets, members.elementCount);
                const x = ChunkedArray.compact(xCenters, true) as ArrayLike<number>;
                const y = ChunkedArray.compact(yCenters, true) as ArrayLike<number>;
                const z = ChunkedArray.compact(zCenters, true) as ArrayLike<number>;
                const count = xCenters.elementCount;
                return Features.create(elementsCount, {
                    x, y, z, count,
                    types: ChunkedArray.compact(types, true) as ArrayLike<FeatureType>,
                    groups: ChunkedArray.compact(groups, true) as ArrayLike<FeatureGroup>,
                    offsets: ChunkedArray.compact(offsets, true) as ArrayLike<number>,
                    members: ChunkedArray.compact(members, true) as ArrayLike<StructureElement.UnitIndex>,
                });
            }
        };
    }
}


text:
.run-status {
    font-family: pokered, pokeplatinum, monospace;
}

.run-status .updating {
    position: absolute;
    right:1em;
}

.last-screenshot {
    margin-bottom:1em;
    padding:1em;
}

.last-screenshot img {
    height:256px;
    margin: 5px;
}

.last-screenshot h4 {
    margin:2px;
}

.itemsList, .badgeList {
    vertical-align: top;
    display: inline-block;
    font-family: pokered, pokeplatinum, monospace;
    margin:2%;
    margin-top:0;
    width:23%;
    min-width: 300px;
}
.itemsList ul, .badgeList ul {
    list-style: none;
    padding:0;
}
.itemsList ul {
    text-align: left;
}
.itemsList ul li{
    padding: .5em 1em;
}
/* .itemsList ul li[data-id]:before {
    content: attr(data-id) ':';
    float: left;
    padding-right: .5em;
    text-align: right;
    width:4.5em;
    box-sizing: border-box;
    vertical-align: baseline;
} */
.itemsList ul li[data-quantity]:after {
    content:'×' attr(data-quantity);
    float: right;
    vertical-align: baseline;
}

.itemsList h6, .badgeList h6 {
    margin: .1em;
}

.gameStats {
    width: auto;
    white-space: nowrap;
}

.gameStats ul li[data-quantity]:after {
    content:attr(data-quantity);
    float: right;
    margin-left: 1em;
    vertical-align: baseline;
}

.optionsList {
    text-transform: capitalize;
}

.badgeList {
    width:auto;
}
.badgeList ul h3 {
    font-family: pokeplatinum, monospace;
}
.badgeList ul h3, .badgeList ul h4 , .badgeList ul h5, .badgeList ul h6 {
    margin:.25em 0;
}

.badgeList ul li {
    display:inline-block;
    background-color: rgba(0,0,0,.1);
    margin:.2em;
    width:12em;
    vertical-align: top;
}

.badgeList ul li .image {
    display: inline-block;
    font-size: 64px;
    width: 1em;
    height: 1em;
    margin: 5px 0;
}

.pixel-art img {
    image-rendering: pixelated!important;
}

.badgeList ul li .image.pokesprite:not(.missingno) img {
    height: 0;
    width: 0;
    padding: .5em;
    background-image: url("../img/pokemon-large.png");
    background-repeat: no-repeat;
    background-size: 1em;
    image-rendering: pixelated;
}

.touhoumon .badgeList ul li .image.pokesprite:not(.missingno) img {
    background-image: url("../img/touhoumon-large.png")!important;
}

.navyblue .badgeList ul li .image.pokesprite:not(.missingno) img {
    background-image: url("../img/navyblue-large.png")!important;
}

.sirius .badgeList ul li .image.pokesprite:not(.missingno) img {
    background-image: url("../img/sirius-large.png")!important;
}

.vega .badgeList ul li .image.pokesprite:not(.missingno) img {
    background-image: url("../img/vega-large.png")!important;
}

.dbzteamtraining .badgeList ul li .image.pokesprite:not(.missingno) img {
    background-image: url("../img/fighters-large.png")!important;
}

.badgeList ul li .image img {
    height: 1em;
}

.hallOfFameDisplay.pokeBorder {
    border:none;
    background-color:white;
    width:95vw;
}
.hallOfFameDisplay.pokeBorder table {
    margin: auto;
}

.hallOfFameDisplay.pokeBorder td {
    background-color: rgba(0,0,0,.1);
}

.hallOfFameDisplay .entry {
    font-size:1.3vw;
}

.entry.fainted {
    filter:grayscale();
}

.run-status .pokeBorder {
    max-width: 90%;
    margin: 1em;
    vertical-align: top;
    padding-left: 1em;
    padding-right: 1em;
}

.pokeBorder .pokedex > h2, .pokeBorder .pokedex > h3, .pokeBorder .pokedex > h4, .pokeBorder .pokedex > h5, .pokeBorder .pokedex > h6 {
    margin:0;
}

.pokeBorder .pokedex .total {
    font-family: pokeplatinum, monospace;
}

.plug {
    display: block;
    margin:.1em;
    color:black!important;
    font-family: pokeplatinum, monospace;
}

.error {
    font-family: pokeplatinum, monospace;
}

.window-shade {
    position: absolute;
    left:.3em;
    top:.5em;
    opacity: .1;
    cursor: pointer;
}

.window-shade:hover {
    opacity: 1;
}

.pokemon-hud ul.party {
  font-family: pokeplatinum, monospace;
  list-style: none;
  margin: 0;
  padding: 0;
  font-size:16px;
}

.pokemon-hud.pc-box ul.party {
    font-size:8px;
    width: 80em;
    text-align: center;
    max-width:100%;
}

.pokemon-hud ul.party > li {
  display: inline-flex;
  position: relative;
  padding: 0;
  margin: .5em;
}

.pokemon-hud.pc-box ul.party > li {
    background-color:#DDD;
    width:15em;
}

.pokemon-hud.pc-box ul.party > li.empty {
    background-color:transparent;
    font-size:3em;
    text-align: center;
    width:auto;
    display: block;
}

.pokemon-hud ul.party > li.female .name:after {
  content: '♀';
  color: deeppink;
}
.pokemon-hud ul.party > li.male .name:after {
  content: '♂';
  color: dodgerblue;
}

.touhoumon .pokemon-hud ul.party > li.female .name:after {
    color:darkmagenta;
    display:inline-block;
	content:"☯";
	transform:rotateZ(-90deg);
}

.touhoumon .pokemon-hud ul.party > li.male .name:after {
    color:darkblue;
    display:inline-block;
	content:"☯";
	transform:rotateZ(90deg);
}

.pokemon-hud ul.party > li .pokemon-image {
  display: inline-block;
  flex: 0 0 auto;
  position: relative;
  height:9em;
}

.pokemon-hud ul.party > li .pokemon-image .species {
    position: absolute;
    bottom:0;
    left:0;
    right:0;
    font-size: 1.2em;
    font-weight: bold;
}

.pokemon-hud ul.party > li.fainted .pokemon-image .species, .pokemon-hud ul.party > li.health-high .pokemon-image .species, .pokemon-hud ul.party > li.health-low .pokemon-image .species {
    color:white;
}

.pokemon-hud ul.party > li .pokemon-image > img, .pokemon-hud ul.party > li .pokemon-image > a > img {
    height:8em;
    image-rendering: pixelated;
}
.pokemon-hud ul.party > li .pokemon-image > .pokesprite > img {
	position: static;
    height:0!important;
    width:0!important;
	transform: none!important;
	font-size:8em;
    padding:.5em;
	margin:auto;
    background-image:url("../img/pokemon-large.png");
    background-repeat: no-repeat;
    background-position: top left;
    background-size: 1em;
    image-rendering: pixelated;
}

.touhoumon .pokemon-hud ul.party > li .pokemon-image > .pokesprite > img {
    background-image: url("../img/touhoumon-large.png")!important;
}

.navyblue .pokemon-hud ul.party > li .pokemon-image > .pokesprite > img {
    background-image: url("../img/navyblue-large.png")!important;
}

.sirius .pokemon-hud ul.party > li .pokemon-image > .pokesprite > img {
    background-image: url("../img/sirius-large.png")!important;
}

.vega .pokemon-hud ul.party > li .pokemon-image > .pokesprite > img {
    background-image: url("../img/vega-large.png")!important;
}

.dbzteamtraining .pokemon-hud ul.party > li .pokemon-image > .pokesprite > img {
    background-image: url("../img/fighters-large.png")!important;
}

.blazingemerald .pokemon-hud ul.party > li .pokemon-image > .pokesprite > img {
    background-image: url("../img/blazing-large.png")!important;
}

.pokemon-hud ul.party > li .pokemon-image > .pokesprite.egg > img {
    background-position: center;
    background: url("../img/egg.gif");
    background-size: contain;
}

.pokemon-hud ul.party > li.pkrs-infected .pokemon-image:before {
    content: '';
    background-size: contain;
    background-repeat: no-repeat;
    background-position: center;
    background-image:url("../img/pkrs-infected.png");
    object-fit: contain;
    position:absolute;
    left: .2em;
    bottom: .2em;
    width: 1.5em;
    height: 1.5em;
    filter: drop-shadow(0 0 1px black);
}

.pokemon-hud ul.party > li.pkrs-infected.pkrs-cured .pokemon-image:before {
    background-image:url("../img/pkrs-cured.png");
    filter: drop-shadow(0 0 1px black)hue-rotate(-45deg);
}

.pokemon-hud ul.party > li .pokemon-info {
  flex: 1 1 auto;
  position: relative;
  min-width: 0;
}
.pokemon-hud ul.party > li .pokemon-info .name {
  display: block;
  text-align: center;
  white-space: pre;
  font-size: 1.2em;
  font-weight: bold;
}
.pokemon-hud ul.party > li .pokemon-info .name:after {
  margin-left: .1em;
}
.pokemon-hud ul.party > li .pokemon-info .types {
  text-align: left;
  white-space: nowrap;
  float:left;
}
.pokemon-hud ul.party > li .pokemon-info .types img {
  height: 1em;
  margin-right: .1em;
  border-radius: 50%;
  position: relative;
}
.pokemon-hud ul.party > li .pokemon-info  .level {
  float: right;
  font-size:1.1em;
  line-height: .9em;
  font-weight: bold;
}
.pokemon-hud ul.party > li .pokemon-info .level:before {
  content: 'Lv';
  font-size: .8em;
  vertical-align: baseline;
}
.pokemon-hud ul.party > li .pokemon-info .moves, .pokemon-hud ul.party > li .pokemon-info .stats {
  list-style: none;
  width: 100%;
  padding: 0;
  margin: 0;
  position: relative;
  top: .3em;
  clear:both;
}
.pokemon-hud ul.party > li .pokemon-info .stats {
    top: 0;
}
.pokemon-hud ul.party > li .pokemon-info .moves li, .pokemon-hud ul.party > li .pokemon-info .stats li  {
  display: block;
  white-space: nowrap;
  height: auto;
  text-align: left;
}
.pokemon-hud ul.party > li .pokemon-info .stats li {
    line-height: .8em;
    height: .8em;
}
.pokemon-hud ul.party > li .pokemon-info .moves li img {
  height: 1em;
  border-radius: 50%;
  position: relative;
  top: .1em;
}
.pokemon-hud ul.party > li .pokemon-info .moves li i {
    margin-right:.2em;
}
.pokemon-hud ul.party > li.fainted {
  opacity: .5;
  transition: filter 0.5s ease-in, opacity 0.5s ease-out;
  filter: grayscale(100%);
}
.pokemon-hud ul.party > li.health-high .pokemon-image {
  background-image: linear-gradient(46deg, green 0%, green 47.6%, rgba(0, 0, 0, 0) 47.7%);
}

.pokemon-hud ul.party > li.health-med .pokemon-image {
  background-image: linear-gradient(46deg, goldenrod 0%, goldenrod 47.6%, rgba(0, 0, 0, 0) 47.7%);
}

.pokemon-hud ul.party > li.health-low .pokemon-image {
  background-image: linear-gradient(46deg, red 0%, red 47.6%, rgba(0, 0, 0, 0) 47.7%);
}

.pokemon-hud ul.party > li .informatic {
    display: block;
    text-align: left;
    clear: both;
}

.pokemon-hud ul.party > li .informatic.evolution {
    line-height: .9em;
    margin-top: .2em;
    margin-bottom: .2em;
}

.pokemon-hud ul.party > li .informatic:before {
    margin-right: .1em;
    width:1em;
    display: inline-block;
    text-align: center;
}

.pokemon-hud ul.party > li .informatic.ability {
    margin-bottom:-.5em;
}
.pokemon-hud ul.party > li .informatic.held-item:before {
    content:'♋';
}
.pokemon-hud ul.party > li .informatic.friendship:before {
    content:'☋';
}

.pokemon-hud ul.party > li .informatic.money:before {
    content:'$';
}

.pokemon-hud ul.party > li .informatic.coins:before {
    content:'◎';
}

.pokemon-hud ul.party > li .informatic.balls:before {
    content:'♎';
}

/*.pokemon-hud ul.party > li.egg {
  line-height: 14vh;
  font-size: 7vh;
}*/

.pokemon-hud ul.party > li.shadow-mon {
    padding-top: 1em;
}

.pokemon-hud ul.party > li.shadow-mon .shadow-bar {
    position: absolute;
    height:1.25em;
    right:.8em;
    left:1.6em;
    top: 0;
    font-size: .75em;
    background-color:#333;
    border:.1em solid #666;
    color: white;
}
.pokemon-hud ul.party > li.shadow-mon .shadow-bar:before {
    content: "❤";
    padding: 0 .5em;
    font-weight: bold;
    background-color:#666;
    transform: skew(-15deg);
    position: absolute;
    right:calc(100% - .5em);
    top:-.075em;
    bottom:-.075em;
    z-index: 1;
}
.pokemon-hud ul.party > li.shadow-mon .shadow-bar:after {
    content:'';
    position: absolute;
    background-color:#666;
    right:-.75em;
    top:-.075em;
    bottom:-.075em;
    width:1em;
    transform:skew(15deg);
}
.pokemon-hud ul.party > li.shadow-mon .shadow-bar .bar {
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    right: 0;
    width: 100%;
    mask-image: repeating-linear-gradient(to right, black 0%, black 19.5%, transparent 19.51%, transparent 20.5%);
    -webkit-mask-image: repeating-linear-gradient(to right, black 0%, black 19.5%, transparent 19.51%, transparent 20.5%);
}
.pokemon-hud ul.party > li.shadow-mon .shadow-bar .bar .shadow {
    position: absolute;
    left:0;
    top:0;
    bottom:0;
    transform:skew(15deg)translateX(-.2em);
    max-width: 100%;
    background-color:purple;
}


text:
<?php

return [
    'count'            => [
        'points'   => ':count point|:count points',
        'comments' => ':count comment|:count comments',
    ],
    'profile'          => 'Profile',
    'login'            => 'Login',
    'register'         => 'Register',
    'logout'           => 'Logout',
    'username'         => 'Username',
    'password'         => 'Password',
    'confirm-password' => 'Confirm password',
    'remember-me'      => 'Remember me',
];


text:
define("ace/snippets/csound_score",["require","exports","module"], function(require, exports, module) {
"use strict";

exports.snippetText = "";
exports.scope = "csound_score";

});
                (function() {
                    window.require(["ace/snippets/csound_score"], function(m) {
                        if (typeof module == "object" && typeof exports == "object" && module) {
                            module.exports = m;
                        }
                    });
                })();


text:
package com.renard.ocr.main_menu;

import android.view.MenuItem;

import androidx.core.app.NavUtils;

import com.renard.ocr.MonitoredActivity;
import com.renard.ocr.R;

public class TipsActivity extends MonitoredActivity {

    protected void onCreate(android.os.Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_help);
        initToolbar();
        setToolbarMessage(R.string.tips);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        getLifecycle().addObserver(findViewById(R.id.youtube_player));
    }

    @Override
    protected int getHintDialogId() {
        return -1;
    }

    @Override
    protected void onPause() {
        super.onPause();
        overridePendingTransition(R.anim.slide_in_left, R.anim.slide_out_right);
    }

    @Override
    public String getScreenName() {
        return "Tips";
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (item.getItemId() == android.R.id.home) {
            NavUtils.navigateUpFromSameTask(this);
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
}


text:
using System.Diagnostics;
using Model = Discord.API.User;

namespace Discord.Rest
{
    [DebuggerDisplay(@"{DebuggerDisplay,nq}")]
    public class RestGroupUser : RestUser, IGroupUser
    {
        internal RestGroupUser(BaseDiscordClient discord, ulong id)
            : base(discord, id)
        {
        }
        internal new static RestGroupUser Create(BaseDiscordClient discord, Model model)
        {
            var entity = new RestGroupUser(discord, model.Id);
            entity.Update(model);
            return entity;
        }

        //IVoiceState
        bool IVoiceState.IsDeafened => false;
        bool IVoiceState.IsMuted => false;
        bool IVoiceState.IsSelfDeafened => false;
        bool IVoiceState.IsSelfMuted => false;
        bool IVoiceState.IsSuppressed => false;
        IVoiceChannel IVoiceState.VoiceChannel => null;
        string IVoiceState.VoiceSessionId => null;
    }
}


text:
package org.kaazing.gateway.service.cluster;

import java.util.Collection;

/**
 * Listener for changed to the global balancer map (balancer URI to collection or balancee URIs across the different gateways)
 */
public interface BalancerMapListener {

    void balancerEntryAdded(String balancerUri, Collection<String> balanceeURIs);
    void balancerEntryRemoved(String balancerUri, Collection<String> balanceeURIs);
    void balancerEntryUpdated(String balancerUri, Collection<String> balanceeURIs);
}


text:
import { ArrayBufferBuilder } from "../../../../utils/ArrayBufferBuilder";
import { BitsReader } from "../../../../utils/BitsReader";
import { SerializerUtils } from "../../../../utils/SerializerUtils";
import { PokerServerLocationData } from "../data/PokerServerLocationData";

export class PokerServerLocationDataSerializer {
	public static serialize(buffer: ArrayBufferBuilder, data: PokerServerLocationData): void {
		buffer.setUint8( data.ID );
			buffer.setANSIStringNullTerminated( data.location );

	}

	public static deserialize(buffer: ArrayBufferBuilder, data: PokerServerLocationData): void {
		data.ID = buffer.getUint8();
			data.location = buffer.getANSIStringNullTerminated();

	}
}


text:
<?php
namespace SelvinOrtiz\Gossip;

/**
 * Class Gossip
 *
 * @author  Selvin Ortiz - https://selvinortiz.com
 * @package SelvinOrtiz\Gossip
 * @version 1.0.0
 */
class Gossip
{
    /**
     * @var static
     */
    protected static $instance;

    /**
     * @var callable[]
     */
    protected $responders = [];

    /**
     * @var callable[]
     */
    protected $once = [];

    protected function __construct() {}
    protected function __cone() {}

    /**
     * @return static
     */
    public static function instance()
    {
        if (static::$instance === null)
        {
            static::$instance = new static();
        }

        return static::$instance;
    }

    /**
     * Registers a callable as an event responder
     *
     * @param string   $name
     * @param callable $responder
     */
    public function listen($name, callable $responder)
    {
        if (!array_key_exists($name, $this->responders)) {
            $this->responders[$name] = [];
        }

        $this->responders[$name][] = $responder;
    }

    /**
     * Registers an callback as an event responder that will remove itself after the first call
     *
     * @param string   $name
     * @param callable $responder
     *
     * @return $this
     */
    public function listenOnce($name, callable $responder)
    {
        if (!array_key_exists($name, $this->once)) {
            $this->once[$name] = [];
        }

        $this->once[$name][] = $responder;
    }

    /**
     * Quietly tells the responders about an event occurrence
     *
     * @param Event $event
     */
    public function whisper(Event $event)
    {
        $responders = $this->getEventResponders($event->name);

        if (!empty($responders)) {
            foreach ($responders as $responder) {
                call_user_func_array($responder, array_merge([&$event], $event->params));
            }
        }
    }

    /**
     * Returns all the registered responders for a given event
     *
     * @param string $name
     *
     * @return array|callable[]
     */
    protected function getEventResponders($name)
    {
        $responders = [];

        if (array_key_exists($name, $this->responders)) {
            $responders = $this->responders[$name];
        }

        if (array_key_exists($name, $this->once)) {
            foreach ($this->once[$name] as $index => $responder) {
                $responders[] = $responder;

                unset($this->once[$name][$index]);
            }
        }

        return $responders;
    }
}


text:
/*
 * The general imports
 *
 * @author Kevin Pho
 */
using System; // For input/output
using System.Collections.Generic; // For collections
using System.Linq; // For selection
using System.Text; // For text manipulation
using System.Threading.Tasks; // For multitasking

/*
 * The local imports
 *
 * @author    Kevin Pho
 */
using Octothorpe = edu.cams.vex.Octothorpe; // For localizing the workspace

/*
 * A compiler framework
 *
 * @author Kevin Pho
 */
namespace edu.cams.vex.Octothorpe {
  /*
   * The main program for executing builds and tests
   *
   * @author Kevin Pho
   */
  class Program {
    // Execution codes
    public static int Success = 0;
    public static int Failure = 1;

    static int Main(string[] args) {
      /* And then,
       * there was light */

      // Print title
      Console.WriteLine("Octothorpe by OmnInfinity");

      /* A world had been made;
       * from creation to destruction */

      /* Tokenizer for lexical analysis */

      // The states to travel between
      Table states = new Table() {
        { "q0", new State("q0").Start().End() },
        { "q1", new State("q1")               },
        { "q2", new State("q2")        .End() },
      };

      // The set of causes and effects for states
      Cause a = delegate (object input) { return "a".Contains((string) input); };
      Effect q0 = delegate (bool input) { return (string) "No input"; };
      Effect q2 = delegate (bool input) { return (string) "Even"; };

      // The set of transitions between states
      states["q0"].Connect(a, states["q1"], q0);
      states["q1"].Connect(a, states["q2"], q2);
      states["q2"].Connect(a, states["q1"], null);

      // The constructed state automaton
      Machine token = new Machine("Token", states);

      // Print out tree
      Console.WriteLine(token.Name + ":");
      Console.WriteLine(token.ToString());

      // Test strings through state automaton
      // token.Accepts("");
      // token.Accepts("a");
      // token.Accepts("aa");

      /* And thus,
       * there was void */

      // Pause and return success
      Console.ReadKey();
      return Program.Success;
    }

    /*
     * The update program for repeating
     *
     * @author    Kevin Pho
     */
    static int Update(string [] args) {
      // Do nothing and return success
      return Program.Success;
    }
  }
}


text:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;

namespace PictureSorter
{
    public partial class Form1 : Form
    {
        List<string> pictureList;
        Dictionary<int, saveDirectoryButton> saveDirectoryButtons;
        int activeIndex;

        static List<string> ImageFormats = new List<string>
        {
            ".jpeg",
            ".jpg",
            ".png",
            ".gif",
            ".bmp",
            ".tiff",
        };

        public Form1()
        {
            InitializeComponent();
        }

        private bool CheckValidImage(string filePath)
        {
            try
            {
                //this caused the file to lock
                //Image image = Image.FromFile(filePath);
                Image image;
                using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
                {
                    image = Image.FromStream(fs);
                }
            }
            catch (ArgumentException ex)
            {
                return false;
            }
            //catch (OutOfMemoryException ex)
            //{
            //    return false;
            //}
            return true;
        }

        private bool CheckValid(string filePath)
        {
            return File.Exists(filePath) && CheckValidImage(filePath);
        }

        private void SetActivePicture(List<string> pictureList, int index)
        {
            if (pictureList.Count > 0)
            {

                bool zoomed = false;
                activePictureBox.Image = null;
                Image image;
                using (FileStream fs = new FileStream(pictureList[index], FileMode.Open, FileAccess.ReadWrite, FileShare.Delete))
                {
                    image = Image.FromStream(fs);
                }
                activeIndex = index;
                activePictureBox.Image = image;
                if (activePictureBox.Size.Height < image.Height || activePictureBox.Size.Width < image.Width)
                {
                    activePictureBox.SizeMode = PictureBoxSizeMode.Zoom;
                    zoomed = true;
                }
                else
                {
                    activePictureBox.SizeMode = PictureBoxSizeMode.CenterImage;
                }
                tooltipStrip.Text = "File: " + Path.GetFileName(pictureList[index]) +
                    "   Height: " + image.Height + "   Width: " + image.Width;
                if (zoomed)
                {
                    double perc = (double)activePictureBox.Size.Height / image.Height;
                    perc = perc * 100;
                    tooltipStrip.Text = tooltipStrip.Text + "   Zoom: " + String.Format("{0:0.##}", perc) + "%";
                }
            }
            else
            {
                activePictureBox.Image = null;
            }
        }

        private void HandleNext()
        {
            if (pictureList != null && pictureList.Count - 1 >= activeIndex + 1)
            {
                SetActivePicture(pictureList, activeIndex + 1);
                if (activeIndex == pictureList.Count - 1)
                {
                    nextButton.Visible = false;
                }
                if (previousButton.Visible == false)
                {
                    previousButton.Visible = true;
                }
            }
        }

        private void HandlePrevious()
        {
            if (pictureList != null && pictureList.Count - 1 >= activeIndex - 1 && activeIndex - 1 != -1)
            {
                SetActivePicture(pictureList, activeIndex - 1);

                if (activeIndex == 0)
                {
                    previousButton.Visible = false;
                }
                if (nextButton.Visible == false)
                {
                    nextButton.Visible = true;
                }
            }
        }

        private void UndoMove(undoMenuItem menuItem)
        {
            //undo move
            File.Copy(menuItem.newPath, menuItem.oldPath);
            File.Delete(menuItem.newPath);
            pictureList.Insert(activeIndex, menuItem.oldPath);
            SetActivePicture(pictureList, activeIndex);
            fileCount.Text = "Total images: " + pictureList.Count;
            this.undoToolStripMenuItem.DropDownItems.Remove(menuItem);
        }

        private void Form1_ResizeEnd(object sender, EventArgs e)
        {
            Form senderForm = sender as Form;
            //if the addDirectoryButton isn't visible (because it would be outside the confines of the form before
            // the resize), check to see if it falls within the confines of the form now
            if (addDirectoryButton.Visible == false)
            {
                //Ensure it is inside the resized form and that is isn't occupying the same location as the nextButton
                if (addDirectoryButton.Location.X + addDirectoryButton.Width < senderForm.ClientRectangle.Width &&
                    addDirectoryButton.Location.X + addDirectoryButton.Width < nextButton.Location.X)
                {
                    addDirectoryButton.Visible = true;
                }
            }
        }

        private void directorySelect_Click(object sender, EventArgs e)
        {
            try
            {
                using (FolderBrowserDialog dialog = new FolderBrowserDialog())
                {
                    dialog.Description = "Open a directory holding the pictures you wish to sort";
                    dialog.ShowNewFolderButton = false;
                    dialog.RootFolder = Environment.SpecialFolder.MyComputer;
                    if (dialog.ShowDialog() == DialogResult.OK)
                    {
                        string folder = dialog.SelectedPath;
                        directoryLabel.Text = "Now sorting - " + folder;
                        pictureList = new List<string>();
                        saveDirectoryButtons = new Dictionary<int, saveDirectoryButton>();
                        foreach (string path in Directory.GetFiles(folder))
                        {
                            if (ImageFormats.Contains(Path.GetExtension(path), StringComparer.OrdinalIgnoreCase) && CheckValid(path))
                            {
                                pictureList.Add(path);
                            }
                        }
                        if (pictureList.Count > 0)
                        {
                            fileCount.Visible = true;
                            fileCount.Text = "Total images: " + pictureList.Count;
                            //imageDetailsLabel.Visible = true;
                            nextButton.Visible = true;
                            sortDirectoriesLabel.Visible = true;
                            addDirectoryButton.Visible = true;
                            SetActivePicture(pictureList, 0);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("Failed to open directory: " + ex.Message);
            }
        }

        private void button_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
        {
            switch (e.KeyCode)
            {
                case Keys.Down:
                case Keys.Up:
                case Keys.Right:
                case Keys.Left:
                    e.IsInputKey = true;
                    break;
            }
        }

        private void button_KeyDown(object sender, KeyEventArgs e)
        {
            //need to override IsInputKey
            //http://msdn.microsoft.com/en-us/library/system.windows.forms.control.keydown%28v=vs.110%29.aspx

            e.Handled = true;

            switch (e.KeyCode)
            {
                case Keys.Right:
                case Keys.Up:
                    HandleNext();
                    break;

                case Keys.Left:
                case Keys.Down:
                    HandlePrevious();
                    break;

                case Keys.D1:
                case Keys.NumPad1:
                case Keys.Oem1:
                    if (saveDirectoryButtons.ContainsKey(1))
                        saveDirectoryButtons[1].PerformClick();
                    break;
            }
        }

        private void form_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.Control && e.KeyCode == Keys.Z)
            {
                if (this.undoToolStripMenuItem.DropDownItems.Count > 0)
                {
                    undoMenuItem lastAdded = (undoMenuItem)this.undoToolStripMenuItem.DropDownItems[this.undoToolStripMenuItem.DropDownItems.Count-1];
                    UndoMove(lastAdded);
                }
            }
        }

        private void nextButton_Click(object sender, EventArgs e)
        {
            HandleNext();
        }

        private void previousButton_Click(object sender, EventArgs e)
        {
            HandlePrevious();
        }

        private void addDirectoryButton_Click(object sender, EventArgs e)
        {
            Button senderButton = sender as Button;

            try
            {
                using (FolderBrowserDialog dialog = new FolderBrowserDialog())
                {
                    dialog.Description = "Open a directory you wish to move pictures to";
                    dialog.RootFolder = Environment.SpecialFolder.MyComputer;
                    if (dialog.ShowDialog() == DialogResult.OK)
                    {
                        string folder = dialog.SelectedPath;
                        string dirName = new DirectoryInfo(folder).Name;

                        int newID;
                        if (saveDirectoryButtons.Count > 0)
                        {
                            newID = saveDirectoryButtons.Keys.Max() + 1;
                        }
                        else
                        {
                            newID = 1;
                        }

                        saveDirectoryButton directoryButton;
                        directoryButton = new saveDirectoryButton();
                        directoryButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
                        directoryButton.Location = senderButton.Location;
                        directoryButton.Name = dirName + "Button";
                        directoryButton.Size = new System.Drawing.Size(41, 26);
                        directoryButton.TabIndex = senderButton.TabIndex - 1;
                        directoryButton.AutoSize = true;
                        directoryButton.Text = dirName;
                        directoryButton.folderPath = folder;
                        directoryButton.ID = newID;
                        directoryButton.Visible = true;
                        directoryButton.UseVisualStyleBackColor = true;
                        directoryButton.Click += new System.EventHandler(this.directoryButton_Click);
                        directoryButton.KeyDown += new System.Windows.Forms.KeyEventHandler(this.button_KeyDown);
                        directoryButton.PreviewKeyDown += new System.Windows.Forms.PreviewKeyDownEventHandler(this.button_PreviewKeyDown);
                        // Add the event handler to allow changing the directory of the folder
                        directoryButton.MouseUp += new System.Windows.Forms.MouseEventHandler(this.directoryButton_MouseUp);
                        this.Controls.Add(directoryButton);

                        System.Windows.Forms.Label directoryButtonLabel;
                        directoryButtonLabel = new System.Windows.Forms.Label();
                        directoryButtonLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
                        directoryButtonLabel.AutoSize = true;
                        directoryButtonLabel.Location = new System.Drawing.Point(directoryButton.Location.X + ((directoryButton.Size.Width/2)-5),
                            directoryButton.Location.Y + directoryButton.Size.Height + 5);
                        directoryButtonLabel.Size = new System.Drawing.Size(10, 10);
                        directoryButtonLabel.Text = newID.ToString();
                        this.Controls.Add(directoryButtonLabel);

                        // Link the label with the button so we can reference it later
                        directoryButton.saveDirectoryButtonLabel = directoryButtonLabel;
                        saveDirectoryButtons.Add(newID, directoryButton);

                        // Figure out where the new button will be placed
                        // If it's outside the bounds of the form, over will be over the nextButton, don't place it, just hide it
                        int newXLoc = senderButton.Location.X + directoryButton.Size.Width + 10;
                        Rectangle formSize = RectangleToScreen(this.ClientRectangle);

                        if (newXLoc + senderButton.Width > formSize.Width || newXLoc + senderButton.Width > nextButton.Location.X)
                        {
                            senderButton.Visible = false;
                            senderButton.Location = new System.Drawing.Point(newXLoc, senderButton.Location.Y);
                            senderButton.TabIndex = senderButton.TabIndex + 1;
                        }
                        else
                        {
                            senderButton.Location = new System.Drawing.Point(newXLoc, senderButton.Location.Y);
                            senderButton.TabIndex = senderButton.TabIndex + 1;
                        }

                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("Failed to open directory: " + ex.Message);
            }

        }
        private void directoryButton_Click(object sender, EventArgs e)
        {
            //move the picture to the directory here
            //var buttonID = saveDirectoryButtons.FirstOrDefault(x => x.Value == sender).Key;
            saveDirectoryButton button = sender as saveDirectoryButton;
            if (button != null && button.folderPath != null)
            {
                string activePicture = pictureList[activeIndex];

                try
                {
                    pictureList.Remove(activePicture);
                    SetActivePicture(pictureList, activeIndex);
                    fileCount.Text = "Total images: " + pictureList.Count;
                    File.Copy(activePicture, button.folderPath + Path.DirectorySeparatorChar + Path.GetFileName(activePicture));
                    File.Delete(activePicture);

                    this.undoToolStripMenuEntry = new undoMenuItem();
                    this.undoToolStripMenuEntry.Name = Path.GetFileName(activePicture);
                    this.undoToolStripMenuEntry.Size = new System.Drawing.Size(124, 22);
                    this.undoToolStripMenuEntry.Text = Path.GetFileName(activePicture) + "  ->  " + button.folderPath;
                    this.undoToolStripMenuEntry.oldPath = activePicture;
                    this.undoToolStripMenuEntry.newPath = button.folderPath + Path.DirectorySeparatorChar + Path.GetFileName(activePicture);
                    this.undoToolStripMenuEntry.Click += new System.EventHandler(this.undoToolStripMenuEntry_Click);

                    this.undoToolStripMenuItem.DropDownItems.Add(this.undoToolStripMenuEntry);
                }
                catch (IOException ex)
                {
                    MessageBox.Show("Failed to move picture: " + ex.Message);
                }
            }
            else if (button != null && button.folderPath == null)
            {
                try
                {
                    using (FolderBrowserDialog dialog = new FolderBrowserDialog())
                    {
                        dialog.Description = "Open a directory you wish to move pictures to";
                        dialog.RootFolder = Environment.SpecialFolder.MyComputer;
                        if (dialog.ShowDialog() == DialogResult.OK)
                        {
                            string folder = dialog.SelectedPath;
                            string dirName = new DirectoryInfo(folder).Name;
                            button.Text = dirName;
                            button.folderPath = folder;
                            button.Name = dirName + "Button";
                            button.saveDirectoryButtonLabel.Visible = true;
                        }
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Failed to open directory: " + ex.Message);
                }
            }
        }

        private void directoryButton_MouseUp(object sender, MouseEventArgs e)
        {
            // When we right click on a button, allow the user to change the save directory
            if (e.Button == System.Windows.Forms.MouseButtons.Right)
            {
                saveDirectoryButton button = sender as saveDirectoryButton;
                if (button != null && button.folderPath != null)
                {
                    try
                    {
                        using (FolderBrowserDialog dialog = new FolderBrowserDialog())
                        {
                            dialog.Description = "Open a directory you wish to move pictures to";
                            dialog.RootFolder = Environment.SpecialFolder.MyComputer;
                            if (dialog.ShowDialog() == DialogResult.OK)
                            {
                                string folder = dialog.SelectedPath;
                                string dirName = new DirectoryInfo(folder).Name;
                                button.Text = dirName;
                                button.folderPath = folder;
                                button.Name = dirName + "Button";
                            }
                            else
                            {
                                DialogResult dialogResult = MessageBox.Show("Do you want to delete this button instead?",
                                    "Delete this button", MessageBoxButtons.YesNo);
                                if (dialogResult == DialogResult.Yes)
                                {
                                    //maybe when we delete instead shuffle the buttons down to replace it's location?

                                    // If we're removing the button, remove the save folder path and replace the text
                                    button.folderPath = null;
                                    button.Text = "+ ";
                                    button.Name = "unassignedsaveDirectoryButton";
                                    // hide the label as well
                                    button.saveDirectoryButtonLabel.Visible = false;
                                }
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show("Failed to open directory: " + ex.Message);
                    }
                }
            }
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void undoToolStripMenuEntry_Click(object sender, EventArgs e)
        {
            undoMenuItem senderItem = sender as undoMenuItem;
            UndoMove(senderItem);
        }

        private void quickHelpToolStripMenuItem_Click(object sender, EventArgs e)
        {
            QuickHelpForm quickHelp = new QuickHelpForm();
            quickHelp.ShowDialog(this);
        }
    }
}


text:
import requests
from bs4 import BeautifulSoup
from mechanize import Browser

import json
import logging
import os
import os.path
from urlparse import urljoin

logger = logging.getLogger('pcppp')
logger.setLevel(logging.INFO)

RESULTS_DIR = 'results'

class ParcelDetail(object):
    def __init__(self, base_url, parcel_number, detail_content):
        self.base_url = base_url
        self.parcel_number = parcel_number

        self._build_attributes(detail_content)

    def _build_attributes(self, detail_content):
        soup = BeautifulSoup(detail_content)

        record_card_pdf_a = soup.find('a', text='Click here.')
        self.record_card_pdf_url = urljoin(
            self.base_url,
            record_card_pdf_a['href'],
        )

        details_pdf_a = soup.find('a', text='Click here to print.')
        self.details_pdf_url = urljoin(
            self.base_url,
            details_pdf_a['href'],
        )

        property_class_th = soup.find('th', text='Property Class:')
        property_class_td = property_class_th.find_next('td')
        self.property_class = property_class_td.get_text()

class ParcelSearchPage(object):
    BASE_SEARCH_URL = 'http://www.xsoftin.com/porter/parcelsearch.aspx'
    FORM_NAME = 'aspnetForm'
    PROPERTY_CLASS_FIELD = 'ctl00$BodyContent$ddlPropClass'
    PROPERTY_CLASS_EXEMPT_VALUE = 'Exempt'
    PAGE_NUM_FIELD_ID = 'ctl00_BodyContent_GridViewParcelSearchResults_ctl28_PageDropDownList'  # NOQA
    PAGE_NUM_FIELD_NAME = 'ctl00$BodyContent$GridViewParcelSearchResults$ctl28$PageDropDownList'  # NOQA
    RESULTS_TABLE_ID = 'ctl00_BodyContent_GridViewParcelSearchResults'
    RESULT_SELECTION_FIELD_NAME = 'ctl00$BodyContent$GridViewParcelSearchResults'  # NOQA
    RESULTS_PER_PAGE = 25

    def __init__(self, browser):
        self.browser = browser

    def get_exempt_parcel_response(self):
        logger.info("Loading parcel search page")
        self.browser.open(self.BASE_SEARCH_URL)
        self.browser.select_form(self.FORM_NAME)

        # Set the property class drop-down to Exempt
        property_class = self.browser.form.find_control(
            self.PROPERTY_CLASS_FIELD,
        )
        property_class.value = [self.PROPERTY_CLASS_EXEMPT_VALUE]

        logger.info("Retrieving %s parcels", self.PROPERTY_CLASS_EXEMPT_VALUE)
        response = self.browser.submit()

        return response

    def get_response_for_page(self, page_number):
        logger.info("Loading search results page %s", page_number)
        self.browser.select_form(self.FORM_NAME)

        # Set the page number drop-down to the appropriate page number
        page_control = self.browser.form.find_control(
            self.PAGE_NUM_FIELD_NAME,
        )
        page_control.value = [str(page_number)]

        response = self.browser.submit()

        return response

    def build_parcel_details(
        self,
        result_content,
        previously_parsed_parcels=None,
    ):
        """
        The search results are in the RESULTS_TABLE_ID table
        as rows with:
            * A header row.
            * Up to RESULTS_PER_PAGE parcels
            * 2 footer rows

        Each actual result row consists of 3 columns:
            * Link field
            * Parcel number
            * Street Address
            * Parcel owner's name

        The link field contains a javascript action
        to post with a value in the RESULTS_SELECTION_FIELD_NAME field
        with a value corresponding to the row number,
        like ``Select$0``.
        """
        soup = BeautifulSoup(result_content)
        results_table = soup.find(id=self.RESULTS_TABLE_ID)

        results_rows = results_table.find_all('tr')
        # We don't care about the header row or two footer rows
        parcel_rows = results_rows[1:-2]

        result_objects = []
        for i, row in enumerate(parcel_rows):
            selector = 'Select$%s' % i

            tds = row.find_all('td')
            assert len(tds) == 4
            parcel_number_td = tds[1]
            parcel_number = parcel_number_td.get_text()

            if parcel_number in previously_parsed_parcels:
                logger.info(
                    "Previously Parsed Parcel Peeped: %s",
                    parcel_number,
                )
                logger.info("Proceeding.")
                # We've already accounted for this one. No need to do it again.
                continue

            logger.info("Retrieving details on parcel %s", parcel_number)

            self.browser.select_form(self.FORM_NAME)
            # Set the appropriate result selection (normally done via
            # javascript)
            # __EVENTTARGET and __EVENTARGUMENT are goofy asp.net
            # things
            self.browser.form.new_control(
                'input',
                '__EVENTTARGET',
                {'value': self.RESULT_SELECTION_FIELD_NAME},
            )
            self.browser.form.new_control(
                'input',
                '__EVENTARGUMENT',
                {'value': selector},
            )
            self.browser.form.fixup()

            response = self.browser.submit()

            result_objects.append(
                ParcelDetail(
                    base_url=response.geturl(),
                    parcel_number=parcel_number,
                    detail_content=response.read(),
                ),
            )

            self.browser.back()

        return result_objects

    def get_current_page_num(self, content):
        soup = BeautifulSoup(content)
        page_num_selection = soup.find(id=self.PAGE_NUM_FIELD_ID)

        selected_option = page_num_selection.find('option', selected=True)
        if not selected_option:
            logger.critical("No page option currently selected.")
            exit(1)

        return int(selected_option['value'])

    def get_max_page_num(self, content):
        soup = BeautifulSoup(content)
        page_num_selection = soup.find(id=self.PAGE_NUM_FIELD_ID)

        page_options = page_num_selection.find_all('option')

        page_numbers = [int(po['value']) for po in page_options]

        return max(page_numbers)

def main():
    b = Browser()
    search_page = ParcelSearchPage(browser=b)

    previously_parsed_parcels = set()
    try:
        with open(
            os.path.join(
                RESULTS_DIR,
                'previously-parsed-parcels.txt',
            ),
            'r',
        ) as previously_parsed_f:
            data_s = previously_parsed_f.read()
            try:
                data = json.loads(data_s)
                previously_parsed_parcels = set(
                    data['previously-parsed-parcels'],
                )
                logger.info(
                    "Loaded %s previously-parsed-parcels",
                    len(previously_parsed_parcels),
                )
            except ValueError:
                logger.warning(
                    "Couldn't parse JSON from previously-parsed-parcels",
                )
    except IOError:
        logger.info(
            "No previously-parsed-parcels found. Starting from scratch.",
        )

    # Perform the search for `Exempt` parcels
    search_response = search_page.get_exempt_parcel_response()

    content = search_response.read()

    max_page_num = search_page.get_max_page_num(content)
    logger.info("Found %s pages of results", max_page_num)

    current_page_num = search_page.get_current_page_num(content)

    while current_page_num <= max_page_num:
        logger.info(
            "Beginning parcel classification for page %s",
            current_page_num,
        )
        response = search_page.get_response_for_page(current_page_num)
        content = response.read()

        parcel_details = search_page.build_parcel_details(
            content,
            previously_parsed_parcels,
        )

        for parcel in parcel_details:
            if '685' in parcel.property_class:
                logger.info(
                    "Downloading PDFs for parcel of category 685: Parcel %s",
                    parcel.parcel_number,
                )
                parcel_dir = os.path.join(RESULTS_DIR, parcel.parcel_number)
                if not os.path.isdir(parcel_dir):
                    os.makedirs(parcel_dir)

                # Download the record card
                path = os.path.join(
                    parcel_dir,
                    'record-card.pdf',
                )
                r = requests.get(parcel.record_card_pdf_url, stream=True)
                if r.status_code != 200:
                    logger.critical("Broken record-card.pdf link.")
                    exit(1)
                with open(path, 'wb') as f:
                    for chunk in r.iter_content(1024):
                        f.write(chunk)

                # Download the details
                path = os.path.join(
                    parcel_dir,
                    'detail.html',
                )
                r = requests.get(parcel.details_pdf_url, stream=True)
                if r.status_code != 200:
                    logger.critical("Broken detail.html link.")
                    exit(1)
                with open(path, 'wb') as f:
                    for chunk in r.iter_content(1024):
                        f.write(chunk)
            else:
                logger.info("Parcel doesn't match: %s", parcel.parcel_number)

            previously_parsed_parcels.add(parcel.parcel_number)

        logger.info("Marking pages parcels as parsed")
        with open(
            os.path.join(
                RESULTS_DIR,
                'previously-parsed-parcels.txt',
            ),
            'w',
        ) as ppp_f:
            data = {
                'previously-parsed-parcels': list(previously_parsed_parcels),
            }
            data_j = json.dumps(data)
            ppp_f.write(data_j)

        current_page_num += 1

    logger.info("Successfully classified all %s pages", max_page_num)

if __name__ == "__main__":
    timed_formatter = logging.Formatter(
        "%(asctime)s%(levelname)s:%(message)s", "%M:%S"
    )
    console_handler = logging.StreamHandler()
    console_handler.setLevel(logging.INFO)
    console_handler.setFormatter(timed_formatter)

    logger.addHandler(console_handler)

    main()